;(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
        typeof define === 'function' && define.amd ? define(factory) : global.layui && layui.define ? layui.define('jquery',function (exports) {
            let $ = layui.jquery;
            exports('Hztree', factory($));
        }) : (global.Hztree = factory($));
})(this,function($){
    "use strict"

    //默认配置
    let defaults = {
        //默认挂载点,用类选择器请确保其只有一个
        selector:'.hztree'
        ,isSimpleNodesTree:true
        ,nodes:null
        ,async:{
            enable:false,
            url:'',
            type:'post',
            data:null,
            dataType: 'json'
        }
        ,view:{
            //根节点的基准padLeft
            basePadLeft:20
            ,increasePadLeft:20
            ,iconPad:5
            ,topNodeIcon:''
            ,topNodeName:'所属部门'
            ,rootIcon:'&#xe679;'
            ,childIcon:'&#xe7e1;'
        }
        ,wholeAddTreeNode:{
            selector:''
            ,eventType:'click'
            ,handel:function(e,levelLessThan3Nodes){}
        }
        ,events:{
            renderBefore($mountedEl,nodes){}
            ,rendered($mountedEl,nodes){}
            ,delTreeNodes($mountedEl,curNodeDom,curNode,childNodes){

            }
            ,addChildNode($mountedEl,curNodeDom,curNode,childNodes){
                //alert("添加子部门")
            }
            ,upNode($mountedEl,curNode,prevNode){}
            ,downNode($mountedEl,curNode,nextNode){}
            ,clickNode(curCheckedNode){}
            ,editNode($mountedEl,curNodeDom,curNode,parentNode){}
        }
    };

    const consts = {
        operate:".operate"
    }

    //保存所有的订阅事件 {Aevent:[pubfun(status,data),pubfun(status,data),...]}
    let subEvents = {};

    //插件类Hztree
    let Hztree = function(options = {}){
        this.utils = Hztree.utils();
        this.options = this.utils.extend({},defaults,options);
        this.el = this.utils.getEl(this.options.selector);
        this.operateEl = null;
        this.curMark = null;
        this.nodes = null;
        this.parentSubNodes = null;
        this.curCheckedNode = null;
        this.ready();
    }

    //工具类
    //为防止创建多个utils对象，我给当前对象一个utils对象
    Hztree.utils = function(){
        return {
            //伪数组转为真数值
            arrayLike(arrLike){
                return Array.from ? Array.from(arrLike) : Array.prototype.slice.call(arrLike);
            }
            //元素相对屏幕偏移量，不需要兼容ie8以下
            ,offset(el){
                let rect = el.getBoundingClientRect()
                    ,sl = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft)
                    ,st = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
                return {
                    l: rect.left + sl,
                    t: rect.top + st,
                    w: el.offsetWidth,
                    h: el.offsetHeight
                };
            }
            //获取相同类名元素
            ,getCls(oParent,className){
                typeof oParent == 'string' && (
                    className = oParent,
                    oParent = null
                )
                oParent = oParent ? oParent : document;
                let classEls = []
                , els = oParent.getElementsByTagName('*')
                , oElsLen = els.length;
                for(let i = 0; i < oElsLen; i++){
                    if(els[i].className == className){
                        classEls.push(els[i]);
                    }
                }
                return classEls;
            }
            /*
            * 根据属性值获取元素
            * pSelector: 父容器
            * selector：目标选择器
            * attrs: {moutel:'.hztree',index:'1'}
            * */
            ,getElByAttrs(pSelector,selector,attrs){
                if(typeof selector == 'object'){
                    attrs = selector
                    selector = pSelector
                    pSelector = null
                }
                let targetEls = []
                    , els = this.query(pSelector,selector)
                if(els){
                    let attrNames = Object.keys(attrs)
                        , attrNamesLen = attrNames.length
                        //是否符合条件
                        , isAccord = function(){
                            let isFlag = true;
                            for(let i = 0; i < attrNamesLen; i++){
                                if(els.getAttribute(attrNames[i]) != attrs[attrName]){
                                    isFlag = false;
                                    break;
                                }
                            }
                            return isFlag;
                        }
                    //id选择器获取的元素本身，而非一个伪数组
                    if(!els.length){
                        let isFlag = isAccord();
                        isFlag && targetEls.push(els)
                    }else{
                        this.arrayLike(els).forEach(el=>{
                            let isFlag = isAccord();
                            isFlag && targetEls.push(el)
                        })
                    }
                }
                return targetEls;
            }
            ,isDOMEl:typeof HTMLElement === 'object'
                ? function(obj) {return obj instanceof HTMLElement;}
                : function(obj) {return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';}
            ,query(oParent,selector){
                if(typeof oParent == 'string'){
                    selector = oParent
                    oParent = null;
                }
                let isIdSelector = /^#[^#]+/.test(selector) , el;
                if(!oParent){
                    el = isIdSelector ? document.querySelector(selector) : document.querySelectorAll(selector)
                }else{
                    el = isIdSelector ? oParent.querySelector(selector) : oParent.querySelectorAll(selector)
                }
                return el;
            }
            ,queryAll(oParent,selector){
                if(typeof oParent == 'string'){
                    selector = oParent
                    oParent = null;
                }
                return  !oParent ? oParent.querySelectorAll(selector) : document.querySelectorAll(selector)
            }
            ,getEl(selector){
                if(this.isDOMEl(selector)){
                    return selector;
                }else{
                    return /^#[^#]+/.test(selector) ? document.querySelector(selector) : document.querySelectorAll(selector)[0];
                }
            }
            ,css(el,cssAttr,val,unit=''){
                //获取属性值
                if(!val && typeof cssAttr == 'string'){
                    return el.currentStyle ? el.currentStyle[cssAttr] : document.defaultView.getComputedStyle(el,false)[cssAttr];
                }
                let setUnit = function (val) {
                    //如果只是数字或小数
                    if(/^(\d?.)?(\d+)?$/.test(val)){
                        unit = 'px'
                    }
                }
                //以对象的方式传值
                if(!val && this.isPlainObject(cssAttr)){
                    for(let cssKey in cssAttr){
                        val = cssAttr[cssKey]
                        setUnit(val)
                        el.style.cssText += ';' +(cssKey + ':' + val+unit)
                    }
                }else{
                    setUnit(val)
                    el.style.cssText += ';' +(cssAttr + ':' + val+unit)
                }
            }
            ,append(targetEl,html){
                if(typeof html == 'string'){
                    //创建html片段流，fragment存放在内存中
                    //将节点全部先追加到html片段流中，最后将html片段流一次性追加至html文档中
                    //而不是一个一个节点的追加到html文档中
                    let fragment = document.createDocumentFragment();
                    let tempEl = document.createElement('div');
                    tempEl.innerHTML = html;
                    let appendEls = [];
                    //firstElementChild只包含元素节点本身
                    //firstChild,包含 元素节点+文本节点+注解
                    while (tempEl.firstElementChild){
                        appendEls.push(tempEl.firstElementChild)
                        fragment.appendChild(tempEl.firstElementChild)
                    }
                    targetEl.appendChild(fragment);
                    return appendEls
                }else{
                    return targetEl.appendChild(html);
                }
            }
            ,closest(el, selector){
                if(!this.isDOMEl(el)){return;}
                let els, targetEl
                ,isSame = (els, el)=>{
                    let len = els.length;
                    for(let i = 0; i<len; i++){
                        if(els[i].isSameNode(el)){
                            return els[i];
                        }
                    }
                    return false;
                }
                ,traversal = (el, selector)=>{
                    els = this.queryAll(el.parentNode, selector);
                    targetEl = isSame(els, el);
                    while(!targetEl){
                        el = el.parentNode;
                        //判断节点是否是html根节点
                        if(el && el.nodeType == el.DOCUMENT_NODE){
                            return false;
                        }
                        traversal(el, selector);
                    }
                    return targetEl;
                };
                return traversal(el, selector);
            }
            ,addEvt(el,eventName,callback,useCapture=false){
                let isHasAddEvtLis = false;
                if(el){
                    if(el.length && el.length > 0){
                        el[0].addEventListener && (isHasAddEvtLis = true)
                    }else{
                        el.addEventListener && (isHasAddEvtLis = true)
                    }
                    if(isHasAddEvtLis) {
                        if(this.isDOMEl(el)){
                            el.addEventListener(eventName, callback, useCapture);
                        }else{
                            let elLen = el.length;
                            for(let i = 0; i < elLen; i++){
                                el[i].addEventListener(eventName, callback, useCapture);
                            }
                        }
                    }
                }
            }
            ,isVisible(el){
                let style= el.style;
                if(style.display == 'none'){
                    return false
                }
                if(style.visibility == 'collapse'|| style.visibility == 'hidden'){
                    return false;
                }
                if(!style.border){
                    if(parseInt(this.css(el,'width')) ==0  || parseInt(this.css(el,'height')) == 0){
                        return false;
                    }
                }
                //元素是否在屏幕窗口范围内
                let winClientWidth = document.documentElement.clientWidth;
                let winClientHeight = document.documentElement.clientHeight;
                let rect = this.offset(el);
                if(!(rect.l > 0 && rect.l < winClientWidth) || !(rect.t > 0 && rect.t < winClientHeight)){
                    return false;
                }
                return true;
            }
            ,hide(el){
                let execBody = (el)=>{
                    this.css(el,'display','none');
                }
                if(this.isDOMEl(el)){
                    execBody(el)
                }else{
                    this.arrayLike(el).forEach(ele=>{
                        execBody(ele);
                    })
                }
            }
            ,show(el){
                let execBody = (el)=>{
                    this.css(el,'display','block');
                }
                if(this.isDOMEl(el)) {
                    execBody(el)
                }else{
                    this.arrayLike(el).forEach(ele=>{
                        execBody(ele);
                    })
                }
            }
            ,attr(el,htmlAttr,val){
                if(!val && typeof htmlAttr == 'string'){
                    return el.getAttribute(htmlAttr)
                }
                if(!val && this.isPlainObject(htmlAttr)){
                    for(let htmlKey in htmlAttr){
                        val = htmlAttr[htmlKey]
                        el.setAttribute(htmlKey,val)
                    }
                }else {
                    el.setAttribute(htmlAttr,val)
                }
            }
            ,eventExtend(targetObj,eventName,callback){
                let oldEvent = targetObj[eventName];
                if(oldEvent == null){
                    targetObj['on'+eventName] = callback;
                }else{
                    targetObj['on'+eventName] = function () {
                        oldEvent();
                        callback();
                    }
                }
            }
            //对象字面量判断
            ,isPlainObject(obj){
                let flag = false;
                if(!obj || typeof obj != 'object'){return flag;}
                if(obj.constructor.prototype.hasOwnProperty("isPrototypeOf")){
                    flag = true;
                }
                return flag;
            }
            //对象深拷贝
            ,extend(){
                let args = this.arrayLike(arguments)
                , target = args.shift();
                args.forEach((arg)=>{
                    let keys = Object.keys(arg);
                    keys.forEach((key)=>{
                        let val = arg[key];
                        if(this.isPlainObject(val) || Array.isArray(val)){
                            let newTarget = Array.isArray(val)?[]:{};
                            //extend()返回给newTarget,再把newTarget值赋值给上一个目标对象 的key
                            !target[key] ? target[key] = this.extend(newTarget,val) : this.extend(target[key],val)
                        }else{
                            target[key] = val;
                        }
                    });
                });
                return target;
            }
            //简单节点树，转为父子节点树
            ,parentSubTree(nodes,options){
                let nodePoint = {},nodesLen = nodes.length,newNodes = [];
                nodes.forEach(node=>{
                    node.children && delete node.children;
                });
                nodes.forEach(node=>{
                    nodePoint[node.id] = node
                })
                nodes.forEach((node,i)=>{
                    options && (
                        options.setDftIcon(node)
                        ,options.setIconPad(node)
                        //isHasDftSort && node.sort == undefined && (node.sort = i)
                    )
                    if(node.pId in nodePoint){//if(nodePoint[node.pid])
                        (nodePoint[node.pId].children || (nodePoint[node.pId].children = [])).push(node);
                    }else{//不在则是顶级节点
                        newNodes.push(node);
                    }
                });
                return newNodes;
            }
            //父子节点树转为简单节点树
            ,parSubTransformSimple(nodes,childName){
                childName = childName || 'children'
                let _self = this, simpleNodes = [];
                for(let i = 0; i < nodes.length; i++){
                    let node = nodes[i];
                    simpleNodes.push(node);
                    getchildNode(node)
                }
                return simpleNodes;
                function getchildNode(node){
                    let childNode = node[childName];
                    if(childNode){
                        simpleNodes = simpleNodes.concat(_self.parSubTransformSimple(childNode));
                    }
                }
            }
            //对父子节点树，根据sort字段排序
            //默认
            ,sortByNodeSortAttr(nodes){
                //diff排序
                let diffSort = function(sortNodes){
                    //仅仅只有一个时
                    if(sortNodes.length == 1){
                        sortNodes[0].sort = 0
                        sortNodes[0].children && diffSort(sortNodes[0].children)
                    }else{
                        sortNodes.sort((a,b)=>{
                            a.children && a.children.length>0 && ( a.children = diffSort(a.children));
                            b.children && b.children.length>0 && ( b.children = diffSort(b.children));
                            (a.sort == undefined || a.sort == null) && (a.sort = sortNodes.indexOf(a));
                            (b.sort == undefined || b.sort == null) && (b.sort = sortNodes.indexOf(b));
                            return a.sort - b.sort;
                        });
                    }
                    return sortNodes;
                };
                return diffSort(nodes);
            }
            //获取删除后的数据
            ,getDeledNodes(nodes,waitDelNodes,isSelf){
                !isSelf && (nodes = nodes.concat())
                let nodesLen = nodes.length,waitDelNodesLen = waitDelNodes.length
                for(let i = 0; i < nodesLen; i++){
                    if(waitDelNodes.length <= 0){return nodes;}
                    for(let j = 0; j < waitDelNodesLen; j++){
                        if(nodes[i].id == waitDelNodes[j].id){
                            nodes.splice(i,1)
                            waitDelNodes.splice(j,1)
                            i--;
                            break;
                        }
                    }
                }
                return nodes;
            }
            //获取当前节点
            ,getCurNode(nodes,nodeId){
                let nodesLen = nodes.length;
                for(let i = 0; i < nodesLen; i++){
                    if(nodes[i].id == nodeId){
                        return nodes[i]
                    }
                }
            }
            //获取父节点下的所有子节点
            ,getChildNodes(nodes,nodeId){
                return nodes.filter((node,i)=>{
                    return node.pId == nodeId
                })
            }
            //获取所有兄弟节点
            ,getSiblingsNodes(nodes,curNode){
                return nodes.filter(node=>{
                    return node.pId == curNode.pid
                })
            }
            //获取当前节点的直接父节点
            ,getParentNode(nodes,curNode){
                let nodesLen = nodes.length;
                for(let i = 0; i < nodesLen; i++){
                    if(curNode.pId == nodes[i].id){
                        return nodes[i]
                    }
                }
            }
            //获取所有上级父节点
            ,getParentNodes(nodes,curNode){
                let parentNodes = [];
                nodes.forEach((node,i)=>{
                    if(curNode.pId == node.id){
                        parentNodes.push(node);
                        parentNodes = parentNodes.concat(this.getParentNodes(nodes,node))
                    }
                });
                return parentNodes;
            }
            //获取顶级节点
            ,getTopNode(nodes,curNode){
                if(!curNode.pId){
                    return curNode;
                }
                let allParentNodes = this.getParentNodes(nodes,curNode)
                return allParentNodes.filter(node=>{
                    return !node.pId
                })[0]
            }
            //获取最大的sort值
            ,getMaxSort(nodes){
                let sorts = [];
                nodes.forEach(node=>{
                    node.push(node.sort)
                })
                return Math.max.apply(null,sorts);
            }
            //获取所有 除去兄弟节点和兄弟节点下的子节点 以及 当前节点和当前下的子节点 的 所有节点
            ,getParentsNodes(nodes,curNode){
                let childNodes = this.getChildNodes(nodes,curNode.id)
                , siblingsNodes = this.getSiblingsNodes(nodes,curNode)
                //获取兄弟节点下的所有子节点
                siblingsNodes.forEach(siblingsNode=>{
                    siblingsNodes = siblingsNodes.concat(this.getChildNodes(nodes,siblingsNode));
                });
                //待删除数组数据
                let tmpDelNodes = childNodes.concat(siblingsNodes,[curNode])
                return this.getDeledNodes(nodes,tmpDelNodes)
            }
            //获取除当前节点及子节点的节点
            ,getNotIncludeCurNodeAndChildNodes(nodes,curNode){
                nodes = nodes.concat()
                let childNodes = this.getChildNodes(nodes,curNode.id)
                childNodes.push(curNode)
                return this.getDeledNodes(nodes,childNodes)
            }
            ,isHasChildNodes(nodes,node){
                let childNodes = []
                nodes.forEach(curNode=>{
                    if(curNode.pId == node.id){
                        childNodes.push(curNode)
                    }
                })
                return childNodes.length > 0 ? childNodes : false;
            }
            //过滤掉pid为空的数据
            ,getRightNode(nodes){
                return nodes.filter(node=>{
                    return node.pId != null;
                })
            }
            //发布订阅模式
            ,pubSubObj(){
                let _self = this;
                //订阅方法subscribe 类似于on / watcher
                let subscribe = function(eventType,handle){
                    !(eventType in subEvents) && (subEvents[eventType] = [])
                    subEvents[eventType].push(handle);
                }
                //发布函数publish 类似于trigger / observe
                //data是数组
                , publish = function(eventType, data){
                    eventType = subEvents[eventType];
                    for (let i = 0; i < eventType.length; i++) {
                        eventType[i].apply(null, data);
                    }
                }
                //删除全部订阅
                , unSubscribe = function(eventType) {
                    subEvents[eventType] && delete subEvents[eventType]
                }
                //通过handle删除指定订阅
                , unSubscribeByFun = function(eventType,handle){
                    eventType = subEvents[eventType];
                    if (eventType) {
                        let handleIndex = eventType.indexOf(handle);
                        if (handleIndex >= 0) {
                            eventType.splice(handleIndex, 1);
                        }
                    }
                }
                return {
                    subscribe,
                    publish,
                    unSubscribe,
                    unSubscribeByFun
                };
            }
        }
    }

    //简单节点树转为父子节点树
    Hztree.prototype.parentSubTree = function(nodes){
        return this.utils.parentSubTree(nodes,{
            setDftIcon: this.setNodeIcon.bind(this),
            setIconPad: this.setIconPad.bind(this),
            //,isHasDftSort:true
        })
    }

    Hztree.prototype.allChildNodes = function(nodeId){
        return this.parentSubTree(this.nodes).filter(node=>{
            return node.id == nodeId
        });
    }

    //获取节点根据nodeId
    Hztree.prototype.getNode = function(nodeId){
        return this.utils.getCurNode(this.nodes,nodeId)
    }

    //新增node节点数据
    Hztree.prototype.setNodeForNodes = function(){

    }

    //获取操作符的节点元素的nodeId
    Hztree.prototype.getCurMarkNodeId = function(){
        let utils = this.utils
        return utils.attr(utils.closest(this.curMark,'li'),'nodeid')
    }

    //是否关闭子树
    Hztree.prototype.isCloseChildTree = function(node){
        return node.open ? '' : ' hz-hidden'
    };

    //获取当前节点和子节点
    Hztree.prototype.getCurNodeAndChildNodes = function(nodeId){
        let childNodes = this.utils.getChildNodes(this.nodes,nodeId)
        return {curNode:this.getNode(nodeId),childNodes:childNodes};
    }


//-----------------------------------------------------------------------------------------------------------------------------------------------


    Hztree.prototype.ready = function(){
        if(!this.el){return;}
        this.getDataWay()
    }

    //数据获取方式
    Hztree.prototype.getDataWay = function(){
        let _self = this
            , asyncObj = this.options.async
            , events = this.events();
        if(asyncObj.enable){
            let deferred = $.ajax({
                url:asyncObj.url
                ,type:asyncObj.type
                ,data:asyncObj.data
                ,dataType:asyncObj.dataType
            });
            deferred.done(nodes=>{
                let parentSubNodes = events.renderBefore(nodes)
                if(parentSubNodes){
                    _self.curCheckedNode = parentSubNodes[0];
                    events.render(parentSubNodes,true)
                    events.rendered(parentSubNodes)
                }
            })
            deferred.fail(nodes=>{
                alert("异步请求失败！！")
            })
        }else{
            let parentSubNodes = events.renderBefore(this.options.nodes);
            if(parentSubNodes){
                _self.curCheckedNode = parentSubNodes[0];
                events.render(parentSubNodes,true)
                events.rendered(parentSubNodes)
            }
        }
    };

    //用函数防止外面调用，只能调用我暴露的接口
    //就算调用也是一个新的内存空间，和当前对象空间不冲突
    Hztree.prototype.events = function(){
        let _self = this
        return {
            //渲染前
            renderBefore(nodes){
                if(!nodes || nodes.length == 0){return;}
                //_self.nodes = _self.utils.getRightNode(nodes);
                _self.nodes = nodes;
                nodes = _self.parentSubTree(nodes);
                _self.utils.sortByNodeSortAttr(nodes);
                //保存父子节点数组
                _self.setParentSubNodes(nodes);
                //console.log(nodes,_self.nodes)
                //对外暴露接口
                _self.options.events.renderBefore(_self.el,_self.nodes);
                return nodes;
            }
            //渲染时
            ,render(nodes,isRenderOperateObj){
                _self.renderTree(_self.el,nodes)
                if(isRenderOperateObj){
                    //渲染操作对象
                    _self.operateEl = _self.utils.append(_self.utils.getEl('body'),_self.renderOperateObj(_self.options.selector))[0];
                }
                //默认选中项
                if(_self.curCheckedNode){
                    _self.setCheckNodeStyle()
                }
                return nodes;
            }
            //渲染结束后
            ,rendered(nodes){
                //对外暴露接口
                _self.options.events.rendered.call(_self,$(_self.el),nodes,_self.nodes);
                //给.operate绑定点击事件
                _self.bindEventByOperate(nodes);
                //给操作节点绑定事件
                _self.bindEventByOperateNodes();
                _self.bindEventByNodes(_self.el,nodes);
                _self.isCloseOperateObj();
                _self.bindEventByWholeAddTreeNode();
            }
        }
    };

    Hztree.prototype.method = function(){
        let _self = this;
        return {
            update(newAddNode,curNode){
                let setAllParentsOpenStatus = function(newAddNode){
                    newAddNode.open = true;
                    let allParentNodes = _self.utils.getParentNodes(_self.nodes,newAddNode);
                    allParentNodes.forEach(node=>{
                        _self.getNode(node.id).open = true;
                    })
                }
                $(_self.el).empty();
                _self.nodes.push(newAddNode)
                let parentSubNodes = _self.events().renderBefore(_self.nodes);
                if(parentSubNodes){
                    _self.curCheckedNode = newAddNode;
                    setAllParentsOpenStatus(newAddNode);
                    _self.events().render(parentSubNodes,false);
                }
            }
            ,edit(curNode){
                let setAllParentsOpenStatus = function(curNode){
                    curNode.open = true;
                    let allParentNodes = _self.utils.getParentNodes(_self.nodes,curNode);
                    allParentNodes.forEach(node=>{
                        _self.getNode(node.id).open = true;
                    })
                };
                $(_self.el).empty();
                let parentSubNodes = _self.events().renderBefore(_self.nodes);
                if(parentSubNodes){
                    _self.curCheckedNode = curNode;
                    setAllParentsOpenStatus(curNode);
                    _self.events().render(parentSubNodes,false);
                }
            }
        }
    }

    Hztree.prototype.renderTree = function(el,nodes){
        //递归--渲染树
        //treeName='root-tree',padLeft=this.options.view.basePadLeft
        let diffRender = (nodes,options)=>{
            let {treeName,padLeft,open} = options
            treeName != 'root-tree' && (padLeft += this.options.view.increasePadLeft)//设置.node-name 的 padding-left
            let tree = '<ul class="'+treeName+open+'" nodelength="'+nodes.length+'">'
            nodes.forEach((node,i)=>{
                //设置层级
                node.level = options.level
                //设置padLeft
                node.padLeft = padLeft
                tree += '<li nodepid="'+node.pId+'" nodeid="'+node.id+'" sort="'+node.sort+'" index="'+i+'">'
                tree +=     '<div class="hz-tree-node">'
                tree +=         '<div class="operate"><i class="hz-iconfont">&#xe600;</i></div>'
                tree +=         '<div class="node-name" style="padding-left:'+padLeft+'px"><i class="hz-iconfont hz-icon-margin-right" style="margin-right:'+node.iconPad+'px">'+node.icon+'</i>'+node.name+'</div>'
                tree +=     '</div>'
                if(node.children && node.children.length){
                    tree+= diffRender(node.children,{
                        treeName:'child-tree'
                        ,padLeft:padLeft
                        ,open:this.isCloseChildTree(node)
                        ,level:node.level+1
                    })
                }
                tree += '</li>'
            });
            tree += '</ul>'
            return tree;
        }
        , hztreeBody = '<div class="hztree-body">'+diffRender(nodes,{
            treeName:'root-tree'
            ,padLeft:this.options.view.basePadLeft
            ,open:''//默认关闭根节点下的子节点
            ,level:1//默认层级
        })+'</div>'
        //向挂载节点中添加内容
        el.innerHTML = hztreeBody;
    };

    //渲染操作对象
    Hztree.prototype.renderOperateObj = function(mountEl){
        let operate = [
            '<div class="operate-body" mountel="'+mountEl+'" style="display: none">',
            '<ul>',
            '<li class="up-node">上移</li>',
            '<li class="down-node">下移</li>',
            '<li class="add-child-node">添加子部门</li>',
            '<li class="edit-child-node">编辑</li>',
            '<li class="del-node">删除</li>',
            '</ul>',
            '</div>'
        ].join('');
        return operate;
    }

    Hztree.prototype.setNodeIcon = function(node){
        let view = this.options.view
        //如果节点没有icon属性
        //若是根节点给默认根节点图标，若是子节点给默认子节点图标
        if(!node.icon){
            node.icon = !node.pId ? view.rootIcon : view.childIcon
        }
        return node;
    }

    Hztree.prototype.setIconPad = function(node){
        let view = this.options.view;
        node.iconPad = node.iconPad ? node.iconPad : view.iconPad;
        return node;
    }

    Hztree.prototype.getParentSubNodes = function(){
        return this.parentSubNodes;
    }

    Hztree.prototype.setParentSubNodes = function(parentSubNodes){
        this.parentSubNodes = parentSubNodes;
    }

    //添加一个默认的顶级节点
    // Hztree.prototype.setDftTopNode = function(nodes){
    //     nodes = nodes.concat()
    //     nodes.unshift({name:this.options.view.topNodeName,id:0,pid:null,sort:0,icon:this.options.view.topNodeIcon,level:0,padLeft:0})
    //     return nodes;
    // }

    //给.operate操作符绑定点击事件
    //用on事件，因为后期会新增节点
    Hztree.prototype.bindEventByOperate = function(){
        let _self = this, prevOperateMark = null
        ,operates = this.utils.query(_self.el,consts.operate);

        $(this.el).on('click','.operate',function(){
            _self.curMark = this;

            //根据操作符 定位操作对象
            _self.posOpereateObjByMark();

            //显示或隐藏操作对象
            prevOperateMark = _self.toggleOperateObj(prevOperateMark);

            //是否隐藏"上移"或"下移"标签
            _self.isHiddenUpOrDownTag();

            //是否隐藏添加子部门
            _self.isHiddenAddChildNode();

            //隐藏或显示编辑
            let node = _self.getNode(_self.getCurMarkNodeId())
            , editChildNode = _self.utils.getCls(_self.operateEl,'edit-child-node')
            node.level>1 ? _self.utils.show(editChildNode) : _self.utils.hide(editChildNode) ;
        });
    };

    //给操作节点绑定事件
    Hztree.prototype.bindEventByOperateNodes = function(){
        let utils = this.utils , pubSubObj = utils.pubSubObj()
        let [_self,$this,el,$mark,$operateBody,nodeId,node,$nodeDom,nodeIndex] = [this]
        ,eventList = {
            "up-node":function(){
                let $prevDom = $nodeDom.prev()
                , prevNodeId = $prevDom.attr('nodeid')
                , prevNode = _self.getNode(prevNodeId)
                , prevIndex = $prevDom.attr("index");

                //对外暴露接口
                _self.options.events.upNode.apply(_self,[
                    $(el)
                    ,node
                    ,prevNode
                ]);

                $operateBody.hide()
                subEvents = {}
                //订阅'upNodeSuc'事件
                pubSubObj.subscribe('upNodeSuc',(isSuc)=>{
                    if(isSuc){

                        //sort值互换
                        let tmp = prevNode.sort;
                        prevNode.sort = node.sort;
                        node.sort = tmp;

                        $prevDom.before($nodeDom)
                        //数据更新
                        $nodeDom.attr('sort',node.sort)
                        $nodeDom.attr('index',prevIndex)
                        $prevDom.attr('sort',prevNode.sort)
                        $prevDom.attr('index',nodeIndex)
                    }
                });
                //_self.method().update(_self.nodes)
            }
            ,"down-node":function(){
                let $nextDom = $nodeDom.next()
                    , nextNodeId = $nextDom.attr('nodeid')
                    , nextNode = _self.getNode(nextNodeId)
                    , nextIndex = $nextDom.attr('index')

                //对外暴露接口
                _self.options.events.downNode.apply(_self,[
                    $(el)
                    ,node
                    ,nextNode
                ])

                subEvents = {}
                $operateBody.hide()
                //订阅'downNodeSuc'事件
                pubSubObj.subscribe('downNodeSuc',(isSuc)=>{
                    if(isSuc){
                        //sort值互换
                        let tmp = nextNode.sort;
                        nextNode.sort = node.sort;
                        node.sort = tmp;

                        $nextDom.after($nodeDom)
                        //数据更新
                        $nodeDom.attr('sort',node.sort)
                        $nodeDom.attr('index',nextIndex)
                        $nextDom.attr("sort",nextNode.sort)
                        $nextDom.attr("index",nodeIndex)
                    }
                })

                //_self.method().update(_self.nodes)
            }
            ,"add-child-node":function(){
                let {curNode,childNodes} = _self.getCurNodeAndChildNodes(nodeId)

                //对外暴露接口
                _self.options.events.addChildNode.apply(_self,[$(el),$nodeDom,curNode,childNodes])
                subEvents = {}
                //订阅'addChildNode'事件
                pubSubObj.subscribe('addChildNode',(isSuc)=>{
                    if(isSuc){

                    }
                })
            }
            ,"del-node":function(){
                let childNodes = utils.getChildNodes(_self.nodes,nodeId);
                //对外暴露接口
                _self.options.events.delTreeNodes.apply(_self,[$(el),$nodeDom,node,childNodes]);

                $(_self.operateEl).hide();
                subEvents = {}
                //订阅'delNodeSuc'事件
                pubSubObj.subscribe('delNodeSuc',(isSuc)=>{
                    if(isSuc){
                        _self.utils.getDeledNodes(_self.nodes,[_self.getNode(nodeId)],true)
                        _self.delDOMTreeNode(nodeId)
                    }
                })
            }
            ,"edit-child-node":function(){
                //对外暴露接口
                _self.options.events.editNode.apply(_self,[$(el),$nodeDom,node,utils.getParentNode(_self.nodes,node)]);
            }
        };
        $(_self.operateEl).find('li').bind('click',function(){
            $this = $(this)
            , el = _self.el
            , $mark = $(_self.curMark)
            , $operateBody = $(_self.operateEl)
            , nodeId = _self.getCurMarkNodeId($mark)
            , node = _self.getNode(nodeId)//当前节点
            , $nodeDom = $mark.closest('li')
            , nodeIndex = $nodeDom.attr('index');
            eventList[$this.attr('class')]()
        });
    }

    //获取dom节点元素
    Hztree.prototype.getDOMTreeNode = function(nodeId){
        return $(this.el).find("li[nodeid='"+nodeId+"']")
    }

    //删除节点及其子节点
    Hztree.prototype.delDOMTreeNode = function(nodeId){
        let $treeNode = this.getDOMTreeNode(nodeId)
        ,$pul = $($treeNode).closest('ul')
        ,liCount = $pul.children('li').size()
        , {curNode,childNodes} = this.getCurNodeAndChildNodes(nodeId)
        , waitDelNodes = childNodes.push(curNode)
        //删除数据
        ,updatedNodes = this.utils.getDeledNodes(this.nodes,waitDelNodes)
        //删除成功
        if(updatedNodes.length != this.nodes){
            this.nodes = updatedNodes;
            if(this.curCheckedNode.id == nodeId){
                if(liCount == 1){
                    this.curCheckedNode = this.utils.getParentNode(this.nodes,this.curCheckedNode);
                    this.setCheckNodeStyle();
                }else{
                    this.curCheckedNode = this.getNode($treeNode.prev().attr('nodeid'));
                    this.setCheckNodeStyle();
                }
            }
            if(liCount == 1){
                $pul.remove()
            }else{
                $treeNode.remove();
            }
        }
    }

    //定位操作对象
    Hztree.prototype.posOpereateObjByMark = function(){
        let curMark = this.curMark;
        let offsetObj = function(react){
            return {
                top:react.t+44,//36+8 36是li的高度 8是三角高度
                left:react.l-5
            }
        };
        offsetObj = offsetObj(this.utils.offset(curMark))
        $(this.operateEl).css({
            'top':offsetObj.top,
            'left':offsetObj.left
        })
        window.addEventListener('resize',()=>{
            //this.utils.css(this.operateEl,offsetObj(this.utils.offset(curMark)))
            $(this.operateEl).css({
                'top':offsetObj.top,
                'left':offsetObj.left
            })
        });
        $(this.el).scroll(()=>{
            //this.utils.css(this.operateEl,offsetObj(this.utils.offset(curMark)))
            $(this.operateEl).css({
                'top':offsetObj.top,
                'left':offsetObj.left
            })
        })
    }

    //给所有节点.node-name绑定点击事件
    Hztree.prototype.bindEventByNodes = function(el,nodes){
        let _self = this
        $(el).on('click','.node-name',function(){
            let $this = $(this)
                , $li = $this.closest('li')
                , $childTree = $this.closest('li').children('.child-tree')
            _self.curCheckedNode = _self.getNode($li.attr('nodeid'))
            if($li.has('.child-tree').length > 0){
                if($li.children().children('.node-name').hasClass('dft-checked-tree-node')){
                    if(!$childTree.is(":visible")){
                        $childTree.slideDown().removeClass('hz-hidden');
                        _self.getNode(_self.curCheckedNode.id).open = true;
                    }else{
                        $childTree.slideUp().addClass('hz-hidden');
                        _self.getNode(_self.curCheckedNode.id).open = false;
                    }
                }
            }else{
                //判断当前节点是否含有子树
            }
            _self.setCheckNodeStyle();
            _self.options.events.clickNode.apply(_self,[_self.curCheckedNode])
        })
    };

    //默认选中的treeNode
    Hztree.prototype.setCheckNodeStyle = function(){
        $(this.el).find('li').find('.node-name').removeClass('dft-checked-tree-node')
        this.getDOMTreeNode(this.curCheckedNode.id).children().children('.node-name').addClass('dft-checked-tree-node');
    }

    //显示与隐藏操作对象
    Hztree.prototype.toggleOperateObj = function(prevOperateMark){
        let operateEl = this.operateEl, utils = this.utils
        if(this.curMark == prevOperateMark){
            utils.isVisible(operateEl) ? utils.hide(operateEl) : utils.show(operateEl)
        }else{
            utils.show(operateEl)
        }
        prevOperateMark = this.curMark
        return prevOperateMark;
    };

    //是否隐藏"上移"或"下移"标签
    Hztree.prototype.isHiddenUpOrDownTag = function(){
        let utils = this.utils
            , ul = utils.closest(this.curMark,'ul')
            , nodeLen = utils.attr(ul,'nodelength')
            , markIndex = utils.attr(utils.closest(this.curMark,'li'),'index')
            , upNode = utils.getCls(this.operateEl,'up-node')
            , downNode = utils.getCls(this.operateEl,'down-node')
            , delNode = utils.getCls(this.operateEl,'del-node')

        let node = this.getNode(this.getCurMarkNodeId());
        if(!node.pId && node.pId != 0){
            utils.hide(upNode)
            utils.hide(downNode)
            utils.hide(delNode)
        }else{
            utils.show(delNode)
            if(markIndex == 0){
                if(nodeLen-1 == 0){
                    utils.hide(upNode)
                    utils.hide(downNode)
                    return;
                }
                utils.hide(upNode)
                utils.show(downNode)
            }else{
                if(nodeLen-1 == markIndex){
                    utils.show(upNode)
                    utils.hide(downNode)
                }else{
                    utils.show(upNode)
                    utils.show(downNode)
                }
            }
        }
    };

    //是否隐藏添加子部门
    Hztree.prototype.isHiddenAddChildNode = function ($this) {
        let utils = this.utils, node = this.getNode(this.getCurMarkNodeId())
        , addChildNode = utils.getCls(this.operateEl,'add-child-node')
        node.level>2 ? utils.hide(addChildNode) : utils.show(addChildNode);
    };

    //点击操作对象外的部分，关闭操作对象
    Hztree.prototype.isCloseOperateObj = function(){
        let _self = this;
        this.utils.eventExtend(document,'click',function (e) {
            if(!_self.curMark){return;}
            e = window.event || e;
            let operateObj = _self.operateEl
            if(e.target.nodeType){
                if(!operateObj.contains(e.target) && !_self.curMark.contains(e.target)){
                    $(operateObj).hide()
                }
            }else{
                $(operateObj).hide()
            }
        });
    };

    //获取顶级节点和前两级
    Hztree.prototype.getLevelLessThan3Nodes = function(nodes){
        return nodes.filter(node=>{
            return node.level < 3;
        })
    }

    //全局“新增节点按钮”事件
    Hztree.prototype.bindEventByWholeAddTreeNode = function(){
        let _self = this,wholeAddTreeNode = this.options.wholeAddTreeNode;
        $(wholeAddTreeNode.selector).unbind().bind(wholeAddTreeNode.eventType,function(e){
            //let nodes = _self.setDftTopNode(_self.nodes)
            wholeAddTreeNode.handel.apply(_self,[e,_self.parentSubTree(_self.getLevelLessThan3Nodes(_self.nodes))])
        })
    }

    //新增node
    Hztree.prototype.addNewTreeNode = function (newAddNode,curNode) {
        //新增节点的pid最大只能是id = 0
        //newAddNode = {id:3,pid:0,icon:'',sort:2,}
        //this.nodes.push(newAddNode);
        this.method().update(newAddNode,curNode);
    }
    
    return Hztree;
});